# -*- coding: utf-8 -*-
import scrapy

import json
import random
import logging
from copy import copy, deepcopy
from FDC_spider.items import FdcEstateGuidItem, FdcBuildingItem, FdcRoomItem

logger = logging.getLogger(__name__)


class ZhuhaiSpider(scrapy.Spider):
    name = 'zhuhai'
    allowed_domains = ['zhbdc.org.cn']
    start_urls = ['https://www.zhbdc.org.cn/estatepubweb/index.html']
    project_li_url = 'https://www.zhbdc.org.cn/estatepubweb/Project/GetProjectList'  # POST 项目列表url
    project_detail_url = 'https://www.zhbdc.org.cn/estatepubweb/Project/GetProjectInfo'  # POST 项目详情url
    building_info_url = 'https://www.zhbdc.org.cn/estatepubweb/Project/GetBuildInfo'  # POST 楼栋信息url

    def start_requests(self):
        """
        项目列表首页
        :return:
        """
        # 构造项目列表首页请求
        headers = {
            'Referer': self.start_urls[0],
            'User-Agent': random.choice(self.settings['USER_AGENTS']),
        }
        data = dict(districtcode="", page=1, rows=9, searchcontent="", )
        yield scrapy.Request(
            self.project_li_url,
            method='POST',
            headers=headers,
            body=json.dumps(data),
            meta=dict(page_num=1, )
        )

    def parse(self, response):
        """
        获取 项目列表
        :param response:
        :return:
        """
        page_num = copy(response.meta['page_num'])
        try:
            resp_dict = json.loads(response.body.decode())
            project_li = resp_dict['data']['projlist']
            assert len(project_li)
            total_num = int(resp_dict['data'].get('total', 1196))
        except:
            logger.error(f'第{page_num}页 项目列表获取失败')
        else:
            headers = {
                'Referer': self.start_urls[0],
            }
            for project_dict in project_li:
                item_eg = FdcEstateGuidItem()
                item_eg['projectName'] = project_dict.get('projectname', None)
                item_eg['districtName'] = project_dict.get('districtname', None)
                item_eg['projectId'] = project_dict.get('projectid', None)
                item_eg['projectAddress'] = project_dict.get('sitnumgather', None)
                item_eg['approvalDate'] = project_dict.get('passdate', None)
                item_eg['totalRoomNo'] = project_dict.get('totalcellcount', None)
                item_eg['soldRoomNo'] = project_dict.get('totalsaleedcount', None)
                item_eg['unsoldRoomNo'] = project_dict.get('totalonsalecount', None)
                if item_eg['projectId']:
                    # 构造POST请求，获取项目详情
                    data = dict(recnumgather=item_eg['projectId'], )
                    yield scrapy.Request(
                        self.project_detail_url,
                        method='POST',
                        headers=headers,
                        body=json.dumps(data),
                        callback=self.parse_project_detail,
                        meta=dict(item_eg=deepcopy(item_eg), ),
                        priority=5,
                    )
                else:
                    logger.error('{}-{} 项目id提取出错'.format(item_eg['districtName'], item_eg['projectName']))

            # 翻页
            total_page = total_num // 9 + 1 if total_num % 9 else total_num // 9
            for next_page_num in range(2, total_page + 1):
                data = dict(districtcode="", page=next_page_num, rows=9, searchcontent="", )
                yield scrapy.Request(
                    self.project_li_url,
                    method='POST',
                    headers=headers,
                    body=json.dumps(data),
                    meta=dict(page_num=next_page_num, )
                )

    def parse_project_detail(self, response):
        """
        获取项目详情
        :param response:
        :return:
        """
        item_eg = copy(response.meta['item_eg'])
        try:
            resp_dict = json.loads(response.body.decode())
            land_info_li = resp_dict['data']['landinfo']
            presale_info_li = resp_dict['data']['presaleinfo']
            assert len(land_info_li) == 1 and len(presale_info_li) == 1
            land_info = land_info_li[0]
            presale_info = presale_info_li[0]
        except:
            logger.error(
                '{}-{}-{} 项目详情获取出错'.format(item_eg['districtName'], item_eg['projectName'], item_eg['projectId']))
        else:
            item_eg['developerName'] = presale_info.get('developer', None)
            item_eg['preSalePermit'] = presale_info.get('qualicert', None)
            x = presale_info.get('x', None)
            y = presale_info.get('y', None)
            item_eg['coordinate'] = (x, y) if x and y else None
            item_eg['preSaleDepositBank'] = presale_info.get('bankname', None)
            item_eg['preSaleAccountNum'] = presale_info.get('bankacounts', None)
            item_eg['certDate'] = presale_info.get('passdate', None)
            item_eg['certStartDate'] = presale_info.get('validstartdate', None)
            item_eg['certExpiryDate'] = presale_info.get('validenddate', None)
            item_eg['projectBrief'] = presale_info.get('recmemo', None)
            item_eg['estateTotalArea'] = presale_info.get('totalarea', None)
            building_floor = self._get_floor_dict(presale_info.get('buildedfloorinfo', None))
            land_usage = land_info.get('landusage', None)
            item_eg['landUse'], item_eg['landUsageTerm'], item_eg['landTerminalDate'] = self._get_land_info(land_usage)
            yield item_eg

            # 构造POST请求，获取楼栋信息
            headers = {
                'Referer': self.start_urls[0],
            }
            data = dict(recnumgather='{}'.format(item_eg['projectId']), buildid="", buildnum="")
            yield scrapy.Request(
                self.building_info_url,
                headers=headers,
                body=json.dumps(data),
                method='POST',
                callback=self.parse_building_info,
                meta=dict(item_eg=deepcopy(item_eg), building_floor=building_floor, ),
                priority=6,
            )

    def parse_building_info(self, response):
        """
        获取楼栋信息
        :param reponse:
        :return:
        """
        item_eg = copy(response.meta['item_eg'])
        building_floor = copy(response.meta['building_floor'])
        # 提取楼栋信息
        try:
            resp_dict = json.loads(response.body.decode())
            building_info = resp_dict['data']['buildinfo'][0]
            building_li = resp_dict['data']['buildname']
            assert building_info and len(building_li)
        except:
            logger.error(
                '{}-{}-{}-{} 楼栋信息提取出错'.format(item_eg['districtName'], item_eg['preSalePermit'], item_eg['projectName'],
                                              item_eg['projectId']))
        else:
            item_bd = FdcBuildingItem()
            item_bd['projectName'] = item_eg['projectName']
            item_bd['projectId'] = item_eg['projectId']
            item_bd['preSalePermit'] = item_eg['preSalePermit']
            item_bd['blockName'] = building_info.get('buildname', None)
            item_bd['buildingId'] = building_info.get('buildid', None)
            item_bd['buildingNo'] = building_info.get('buildnum', None)
            item_bd['approvalRoomNo'] = building_info.get('cansalecellcount', None)
            item_bd['approvalArea'] = building_info.get('cansalecellarea', None)
            item_bd['soldRoomNo'] = building_info.get('saleedcellcount', None)
            item_bd['buildingSoldArea'] = building_info.get('saleedcellarea', None)
            item_bd['saleableRoomNo'] = building_info.get('onsalecellcount', None)
            item_bd['buildingSaleableArea'] = building_info.get('onsalecellarea', None)
            item_bd['floorTotalNo'] = building_floor.get(item_bd['blockName'], None)
            yield item_bd

            # 获取房号列表
            try:
                room_li = resp_dict['data']['housesrc']
                assert len(room_li)
            except:
                logger.error(
                    '{}-{}-{}-{}  房号列表获取出错'.format(item_bd['preSalePermit'], item_bd['projectName'],
                                                   item_bd['projectId'], item_bd['blockName'], ))
            else:
                for room_dict in room_li:
                    item_rm = FdcRoomItem()
                    item_rm['projectName'] = item_bd['projectName']
                    item_rm['projectId'] = item_bd['projectId']
                    item_rm['blockName'] = item_bd['blockName']
                    item_rm['buildingId'] = item_bd['buildingId']
                    item_rm['roomLocation'] = room_dict.get('sitnumgather', None)
                    item_rm['roomStructure'] = room_dict.get('housetypename', None)
                    item_rm['roomUse'] = room_dict.get('houseusagename', None)
                    item_rm['saleStatus'] = room_dict.get('housestatename', None)
                    item_rm['roomArea'] = room_dict.get('archarea', None)
                    item_rm['innerArea'] = room_dict.get('roomarea', None)
                    item_rm['apportionmentArea'] = room_dict.get('apportarea', None)
                    item_rm['roomFloor'] = room_dict.get('logicfloornum', None)
                    item_rm['roomNo'] = room_dict.get('doornum', None)
                    item_rm['unitName'] = room_dict.get('unitnum', None)
                    yield item_rm

            # 构造POST请求，获取项目其它楼栋信息
            if len(building_li) > 1:  # 楼栋总数大于1，才构造请求
                headers = {
                    'Referer': self.start_urls[0],
                }
                for bd_dict in building_li[1:]:  # 从第二个楼栋开始获取
                    data = dict(recnumgather=bd_dict['recnumgather'], buildid=bd_dict['buildid'],
                                buildnum=bd_dict['buildnum'])
                    yield scrapy.Request(
                        self.building_info_url,
                        headers=headers,
                        body=json.dumps(data),
                        method='POST',
                        callback=self.parse_building_info,
                        meta=dict(item_eg=deepcopy(item_eg), building_floor=building_floor, ),
                        priority=7,
                    )

    @staticmethod
    def _get_land_info(_str: str or None) -> tuple:
        """
        提取土地用途、使用年限、终止日期
        :param _str:
        :return:
        """
        try:
            ret_li = _str.split(',')
            land_use = ret_li[0].split('：')[1]
            land_usage_term = ret_li[1].split('：')[1]
            land_date = ret_li[2].split('：')[1]
        except:
            return None, None, None
        else:
            return land_use, land_usage_term, land_date

    @staticmethod
    def _get_floor_dict(_str: str) -> dict:
        """
        提取楼层字典
        :param _str:
        :return:
        """
        try:
            ret_li = _str.split(';')
            floor_dict = {i.split('/')[0]: i.split('/')[1] for i in ret_li}
        except:
            return dict()
        else:
            return floor_dict
